package nsalt.fetch.branch

import chisel3._
import chisel3.util._

import nsalt._

// Feedback is issued by the write-back stage. And will be used for 
// determining take the branch or flush the whole pipeline.
//
// The Feedback bundle here can be considered as a protocol between
// the write-back (WB) and the branch-prediction (BP) module. As a
// convention, we declare the protocol at the place where the data
// is accepted, instead of issued.

class Predict extends Module {

  val io = IO(new Bundle{
    val in  = new PredictPort()
    val out = new RedirectPort()
  })

  // Put a Branch Target Buffer (BTB) && Pattern History Table (PHT)

  val bufferEntryCount = 512
  val addr = new EntryAddr(log2Up(bufferEntryCount))
  val btb = Module(new TargetBuffer(bufferEntryCount, addr))
  val pht = Module(new PatternHistory(bufferEntryCount, addr))

  // Put a Return Address Stack (RAS)
 
  val stackEntryCount = 16
  val ras = Module(new ReturnAddressStack(stackEntryCount))

  // Connect'em all
 
  btb.io.in <> io.in
  pht.io.in <> io.in
  ras.io.in <> io.in

  val returnTarget = ras.io.out.target
  val branchTarget = btb.io.out.target
  val branchType   = btb.io.out.branchType

  val branchTaken  = pht.io.out.asBool()

  io.out.dest := Mux(branchType === BranchType.R, returnTarget, branchTarget)
  io.out.valid := btb.io.hit && Mux(branchType === BranchType.B, branchTaken, true.B)
  io.out.wholeFlushed := 0.U
}
